package SC12Project.Milestone1.Payment;

import java.io.File;
import java.io.FileNotFoundException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

/**
 * Service provider for a Payment system.
 * 
 * @author Stefanos
 * 
 */
public class PaymentProvider implements PaymentWS {

	private BanKInfo bankInfo;

	private File f;

	/*
	 * public static void main(String... args){ PaymentProvider pp = new PaymentProvider(); System.out.println("stef has " + pp.queryAccount("stef")); System.out.println("vasia has " + pp.queryAccount("vasia")); try { if (pp.transfer("stef","vasia",10)) { System.out.println("stef has " + pp.queryAccount("stef")); System.out.println("vasia has " + pp.queryAccount("vasia")); } } catch (TransactionException e) { e.printStackTrace(); }
	 * 
	 * 
	 * }
	 */

	public PaymentProvider() {
		parseAndInit("../datasource/ds_2_3.xml");
	}

	void parseAndInit(String path) {
		this.f = new File(path);
		/*
		 * try {
		 * 
		 * JAXBContext context = JAXBContext.newInstance(BanKInfo.class); this.u = context.createUnmarshaller(); this.m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); this.bankInfo = (BanKInfo) u.unmarshal(f);
		 * 
		 * bankInfo.getAccount().get(0).setAmount(100); this.m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); m.marshal(bankInfo,f);
		 * 
		 * 
		 * } catch (JAXBException e) { e.printStackTrace(); }
		 */

		try {
			ClassLoader cl = SC12Project.Milestone1.Payment.ObjectFactory.class.getClassLoader();
			String packageName = BanKInfo.class.getPackage().getName();
			JAXBContext jc = JAXBContext.newInstance(packageName, cl);
			Unmarshaller u = jc.createUnmarshaller();
			@SuppressWarnings("unchecked")
			JAXBElement<BanKInfo> root = (JAXBElement<BanKInfo>) u.unmarshal(f);
			bankInfo = root.getValue();

		} catch (JAXBException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * Query the balance of an account
	 * 
	 * @param accountID
	 * @return balance of the account
	 */
	@Override
	public int queryAccount(String accountID) {
		int balance = 0;
		int i = 0;
		for (i = 0; i < this.bankInfo.getAccount().size(); i++) {
			if (this.bankInfo.getAccount().get(i).getAccountID().equals(accountID)) {
				balance = this.bankInfo.getAccount().get(i).getAmount();
			}
		}
		return balance;
	}

	/**
	 * Transfer money from account1 to account2
	 * 
	 * @param accountID1
	 *            payee
	 * @param accountID2
	 *            benefiter
	 * @param amount
	 *            the amount of money transfered from account1 to account2
	 * @return true if the transaction is successful; otherwise false;
	 */
	/*
	 * (non-Javadoc)
	 * 
	 * @see SC12Project.Milestone1.Payment.PaymentWS#transfer(java.lang.String, java.lang.String, int)
	 */
	@Override
	public boolean transfer(String accountID1, String accountID2, int amount) throws TransactionException {
		if (amount > 0) {
			int i = 0;
			int j = 0;
			int newBalance = 0;
			boolean transferValid;
			boolean account1Exists = false;
			boolean account2Exists = false;
			for (i = 0; i < this.bankInfo.getAccount().size(); i++) { // search for account ID1
				if (this.bankInfo.getAccount().get(i).getAccountID().equals(accountID1)) { // if account ID1 is found
					account1Exists = true;
					for (j = 0; j < this.bankInfo.getAccount().size(); j++) { // search for account ID2
						if ((this.bankInfo.getAccount().get(j).getAccountID().equals(accountID2)) && i != j) { // if account ID2 is found
							account2Exists = true;
							if (((this.bankInfo.getAccount().get(i).getAmount()) - amount) >= 0) { // Check if the payee can send the money

								/* for the payee */
								newBalance = this.bankInfo.getAccount().get(i).getAmount() - amount;
								this.bankInfo.getAccount().get(i).setAmount(newBalance);
								/* for the benefiter */
								newBalance = this.bankInfo.getAccount().get(j).getAmount() + amount;
								this.bankInfo.getAccount().get(j).setAmount(newBalance);
								/* update xml file */
								try {
									this.marshalIntoXMLFile();
								} catch (JAXBException e) {
									e.printStackTrace();
								} catch (FileNotFoundException e) {
									e.printStackTrace();
								}
								transferValid = true;
								return transferValid;
							} else {
								throw new TransactionException("Payee's balance is not enough for the transaction");
							}
						}
					}
				}
			}
			/*
			 * transferValid=false; return transferValid;
			 */
			if (!account1Exists) {
				throw new TransactionException("ID account 1 does not exist");
			}
			if (!account2Exists) {
				throw new TransactionException("ID account 2 does not exist");
			}
		} else {
			throw new TransactionException("You cannot transfer negative or zero amount of money");
		}
		return false;
	}

	void marshalIntoXMLFile() throws JAXBException, FileNotFoundException {
		ClassLoader cl = SC12Project.Milestone1.Payment.ObjectFactory.class.getClassLoader();
		String packageName = BanKInfo.class.getPackage().getName();
		JAXBContext jc = JAXBContext.newInstance(packageName, cl);
		Marshaller m = jc.createMarshaller();
		m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
		ObjectFactory obf = new ObjectFactory();
		JAXBElement<BanKInfo> output = obf.createBank(bankInfo);
		m.marshal(output, f);
	}

}
